import java.awt.*;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;

/**
 * A játék belépési pontját tartalmazó, és a megjelenítésért és irányításáért
 * felelős osztály.
 * Megvalósítja az IVisualizer interfacet, ezen keresztül kapcsolódik a
 * modelhez.
 */
public class View extends JFrame implements IVisualizer, KeyListener
{
  private ArrayList entityViews;
  private Game game;
  private boolean loading = false;
  private Image offscreen;
  private int column = 1, line = 1;

  /**
  * A program belépési pontja.
  * @param args
  */
  public static void main(String[] args)
  {
    Game game = new Game();
    View view = new View(game);
    game.addVisualizer(view);

    game.init();
  }

  /**
   * A konstruktor, beállítja az ablak alap adatait.
   * @param Refrencia a modelre.
   */
  public View(Game game)
  {
    this.game = game;
    entityViews = new ArrayList();

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setFrameSize(300, 300);

    this.setTitle("JuzKez by Macrohard");
    this.addKeyListener(this);
    this.setResizable(false);

  }

  /**
   * Az ablakot újra rajzoló függvény.
   * @param g
   */
  public void paint(Graphics g)
  {
    offscreen = createImage(g.getClipBounds().width,g.getClipBounds().height);
    Graphics2D g2d = (Graphics2D) offscreen.getGraphics();

    g2d.setColor(Color.darkGray);
    g2d.fill(g.getClip());

    Insets inset = this.getInsets();

    int startLeft = inset.left;
    int startTop = inset.top;

    Image img = null;

    try 
    {
      img = ImageIO.read(new File(game.getMainDir()+ "images\\field.png"));
    }
    catch (IOException ex)
    {

    }

    //üres mezők kirajzolása
    if(img != null)
    {
      for(int i = 0;i<line;i++)
      {
        for(int j = 0;j<column;j++)
        {
          int x = startLeft + j*35;
          int y = startTop + i*42 + (j%2 != 0 ? 21 : 0);

          g2d.drawImage(img, x, y, null);
        }
      }
    }

    //Az Entity kirajzolók segítségével a pálya tartalmának kirajzolása.
    for(int i = 0;i<entityViews.size();i++)
    {
      ((EntityView)entityViews.get(i)).draw(g2d, this.getInsets());
    }

    g2d.setColor(Color.white);

    g2d.fillRect(1, 1, 20 , 20);

    g.drawImage(offscreen, 0, 0, null);

    g2d.dispose();
  }

  /**
   * Beállítja az ablakunk méretét.
   * @param width
   * @param height
   */
  private void setFrameSize(int width, int height)
  {
 //   this.setSize(width, height);
    this.setPreferredSize(new Dimension(width, height));
    this.pack();
  }

  /**
   * Invalidálja az ablakunkat, beállítja a méretét a pályaméretének
   * megfelelően.
   */
  public void invalidate()
  {
    if(loading)
    {
      this.setVisible(!loading);
    }
    else
    {
      column = game.getColumns();
      line = game.getLines();

      Insets inset = this.getInsets();

      setFrameSize(28 + column*35, line*42 + (line%2)*21 + (inset.bottom + inset.top));

      this.setVisible(!loading);
      this.repaint();
    }
  }

  /**
   * Az újonnan léterjött Entityket a megjelenytéshez regisztrálja.
   * Mindegyikhez létrehoz egy hozzátartozó EntityViewra épülő megjelenytő
   * osztályt.
   * @param entity Az új Entity referenciája.
   */
  public void register(Entity entity)
  {
      EntityView ev = null;

      if(entity instanceof Wall)
      {
        ev = new WallView();
      }
      else if(entity instanceof Player)
      {
        ev = new PlayerView();
      }
      else if(entity instanceof Exit)
      {
        ev = new ExitView();
      }
      else if(entity instanceof Sandstone)
      {
        ev = new SandstoneView();
      }
      else if(entity instanceof Diamond)
      {
        ev = new DiamondView();
      }
      else if(entity instanceof Granite)
      {
        ev = new GraniteView();
      }
      else if(entity instanceof Bomb)
      {
        ev = new BombView();
      }
      else if(entity instanceof Uranium)
      {
        ev = new UraniumView();
      }
      else if(entity instanceof Tracker)
      {
        ev = new TrackerView();
      }
      else if(entity instanceof Multiplier)
      {
        ev = new MultiplierView();
      }
      else if(entity instanceof Boulder)
      {
        ev = new BoulderView();
      }
      else if(entity instanceof Gemster)
      {
        ev = new GemsterView();
      }

      if(ev != null)
      {
        ev.setEntity(entity);
        ev.setGame(game);
        ev.setView(this);
        entity.addObserver(ev);
        entityViews.add(ev);
      }

      invalidate();
  }

  /**
   * Az IVisualizer tagfüggvénye. Jelzi, hogy a játék épp töltődik.
   * @param load
   */
  public void setLoading(boolean load)
  {
    loading = load;
    invalidate();
  }

  /**
   * Az IVisualizer tagfüggvénye. Jelzi, hogy a játék elindult.
   * @param start
   */
  public void gameStarted(boolean start)
  {
    invalidate();
  }

  public void keyTyped(KeyEvent e) {}

  public void keyPressed(KeyEvent e)
  {
    char key = e.getKeyChar();

    switch(key)
    {
      //JuzKez
      case 'a':
        game.step(6, 0);
        break;
      case 'q':
        game.step(1, 0);
        break;
      case 'w':
        game.step(2, 0);
        break;
      case 'e':
        game.step(3, 0);
        break;
      case 'd':
        game.step(4, 0);
        break;
      case 's':
        game.step(5, 0);
        break;
      case 'y':
        game.setBomb(0);
        break;
        
      //JuzLab
      case 'm':
        game.step(4, 1);
        break;
      case 'k':
        game.step(3, 1);
        break;
      case 'j':
        game.step(2, 1);
        break;
      case 'h':
        game.step(1, 1);
        break;
      case 'n':
        game.step(5, 1);
        break;
      case 'b':
        game.step(6, 1);
        break;
      case 'x':
        game.setBomb(1);
        break;

      //Menu
      case 'r':
        game.reset();
        break;
    }
  }

  public void keyReleased(KeyEvent e) {}

  /**
   * Eldobja az összes tárolt megjelenytő referenciát.
   */
  private void clearViews()
  {
    for(int i = 0;i<entityViews.size();i++)
    {
      ((EntityView)entityViews.get(i)).entity.removeObserver((EntityView)entityViews.get(i));
    }

    entityViews.clear();
  }

  public void reset()
  {
    clearViews();
  }

  public void playerKilled(int lives)
  {
    String text = "";
    if(lives >= 0)
    {
      text = "Mindkét játékos meghalt. Még "+ lives + " élet van hátra, a pálya újraindul.";
    }
    else
    {
      text = "Mindkét játékos meghalt. A játék véget ért.";
    }
    JOptionPane.showMessageDialog(this, text);
  }
}